/**
 * 
 */
package truerefactor.metrics;

import java.util.ArrayList;
import java.util.List;

import truerefactor.graph.AttributeNode;
import truerefactor.graph.ClassNode;
import truerefactor.graph.CodeGraph;
import truerefactor.graph.CodeNode;
import truerefactor.graph.MethodNode;

/**
 * CBO - An implementation of the Coupling Between Objects metric
 * 
 * @author Isaac Griffith
 */
public class CBO extends Metric {

    /**
     * Creates a new instance of the CBO metric
     */
    public CBO()
    {
        this.shortName = "CBO";
        this.name = "Coupling Between Objects";
        this.description = "";
    }

    /*
     * (non-Javadoc)
     * @see truerefactor.metrics.Metric#measure()
     */
    @Override
    public double measure(CodeGraph graph)
    {
        // CBO = The amount of collaborations between a class and other classes
        // Low CBO = Low Coupling = Good

        List<ClassNode> classes = graph.getClasses();
        double cCBO = 0;
        double tCBO = 0;
        double mCBO = 0;

        for (ClassNode cNode : classes)
        {
            cCBO = measure(cNode, graph);
            tCBO += cCBO;
        }

        // System.out.println("tCBO: " + tCBO);
        mCBO = (tCBO / classes.size());

        // System.out.println("mCBO: " + mCBO);
        return mCBO;
    }

    /**
     * Provides a static measurement of the provided class in the provide graph
     * 
     * @param cNode
     *            ClassNode to be measured
     * @param graph
     *            Graph containing the provided ClassNode
     * @return CBO measurement for the provided classnode
     */
    public static int measure(ClassNode cNode, CodeGraph graph)
    {
        int count = 0;

        count += cNode.getAssociatedClasses().size();

        for (CodeNode node : cNode.getAttributes())
        {
            AttributeNode attr = (AttributeNode) node;
            if (attr == null)
                continue;
            if (attr.getAssociatedClass() != null)
            {
                if (attr.getAssociatedClass() != null && attr.getAssociatedClass().equals(attr.getParent()))
                {
                    count++;
                }
            }
        }

        for (CodeNode node : cNode.getMethods())
        {
            MethodNode method = (MethodNode) node;

            List<ClassNode> otherClasses = new ArrayList<ClassNode>();
            for (MethodNode mNode : method.getOtherMethods())
            {
                if (otherClasses.contains(mNode.getParentClass()))
                    continue;
                otherClasses.add(mNode.getParentClass());
            }

            for (AttributeNode aNode : method.getOtherAttributes())
            {
                if (otherClasses.contains(aNode.getParent()))
                    continue;
                otherClasses.add(aNode.getParent());
            }

            count += otherClasses.size();
        }

        return count;
    }
}
